﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Core.Entities;
using Core.Enums;
using Core.Writer;
using System.Collections;
using Core.Tools;
using Core.ObjectOperate.ReflectionImpl;

namespace Core.ReadWriter
{
    [Serializable]
    public class LateTypeReadWriter : BaseReadWriter
    {
        private static readonly object NullValue = new object();

        private RWTypes InternalObjectType = 0;

        private readonly Type Type;

        private BaseReadWriter InternalReadWriter;

        public BaseReadWriter ReadWriter
        {
            get
            {
                if (InternalReadWriter == null)
                {
                    throw new Exception("ObjectType must be specified.");
                }

                return InternalReadWriter;
            }
        }

        public LateTypeReadWriter(Type Type, object Content, RWSigns Sign = RWSigns.ChangeType | RWSigns.Property) : base(Content == null ? NullValue : Content, Sign)
        {
            this.Type = Type;
        }

        public LateTypeReadWriter(RWSigns Sign = RWSigns.ChangeType | RWSigns.Property) : base(NullValue, Sign)
        {
            Type = typeof(object);
        }

        public LateTypeReadWriter(object Content, RWSigns Sign = RWSigns.ChangeType | RWSigns.Property) : base(Content == null ? NullValue : Content, Sign)
        {
            Type = InternalContent.GetType();
        }


        public override object this[string Name]
        {
            get
            {
                return ReadWriter[Name];
            }
            set
            {
                ReadWriter[Name] = value;
            }
        }

        public override object this[int Index]
        {
            get
            {
                return ReadWriter[Index];
            }
            set
            {
                ReadWriter[Index] = value;
            }
        }

        public override IEnumerable<string> Fields { get { return ReadWriter.Fields; } }

        public override int Count
        {
            get
            {
                return ReadWriter.Count;
            }
        }

        public override RWTypes ObjectType
        {
            get
            {
                return InternalObjectType;
            }
            set
            {
                switch (value)
                {
                    case RWTypes.Table:
                        InternalReadWriter = new TableReadWriter(InternalContent == NullValue ? new Table() : (Table)InternalContent, Type, Sign);
                        break;
                    case RWTypes.Object:
                        InternalReadWriter = new DictionaryReadWriter(InternalContent == NullValue ? new Dictionary<string, object>() : (IDictionary)InternalContent, Type, Sign);
                        break;
                    case RWTypes.Array:
                        InternalReadWriter = new ListReadWriter(InternalContent == NullValue ? new List<object>() : (IList)InternalContent, Type, Sign);
                        break;
                    default:
                        throw new FormatException("ObjectType");
                }

                InternalObjectType = value;
            }
        }

        public override void Add(string Name, object Value)
        {
            ReadWriter.Add(Name, Value);
        }

        public override IDataWriter CreateChildrenWriter(CreateChildrenWriterInfo Info)
        {
            return ReadWriter.CreateChildrenWriter(Info);
        }

        public override void Next()
        {
            ReadWriter.Next();
        }

        public override bool Read()
        {
            return ReadWriter.Read();
        }

        public override void Reset()
        {
            ReadWriter.Reset();
        }

        public override bool TryGetValue(string Name, out object Value)
        {
            return ReadWriter.TryGetValue(Name, out Value);
        }

        public override object Content
        {
            get
            {
                return ReadWriter.Content;
            }
        }
    }
}